package com.share.dymamic.datasource;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Iterator;
import java.util.Properties;
import java.util.logging.Logger;

import javax.sql.DataSource;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;

import com.share.dymamic.configer.CenterPropertyPlaceholderConfigurer;
import com.share.dymamic.utils.EncryptUtils;
/** 
* 
* 根据项目所在环境（测试环境、预发布环境、线上环境）动态地改变数据源的属性
* @author weigen.ye 
* @date 创建时间：2016年11月11日 下午9:18:47 
*
*/
public class MyDataSource implements DataSource, InitializingBean, BeanNameAware{
	private String beanName;
	private DataSource dataSource;
	
	public void afterPropertiesSet() throws Exception{
		Properties properties = CenterPropertyPlaceholderConfigurer.getDataSourceProperties(this.beanName);
	    if (properties == null) {
	    	throw new RuntimeException("Can't load dataSource properties:[" + this.beanName + ".properties] from config center!");
	    }
	
	    initDataSource(properties);
	
		System.out.println("***********************MyDataSource********************");
		System.out.println("  DataSource【" + this.beanName + "】 is loaded!  ");
		System.out.println("************************************************************");
	}

	private void initDataSource(Properties properties){
		String dataSourceClassName = properties.getProperty("jdbc.dataSourceClassName");
		try {
		    this.dataSource = (DataSource) (Thread.currentThread().getContextClassLoader().loadClass(dataSourceClassName).newInstance());
		    setDataSourceProperties(this.dataSource, properties);
		}catch (ClassNotFoundException e) {
			throw new RuntimeException("DataSourceClassName [" + dataSourceClassName + "] not found:", e);
		}catch (Exception e) {
			throw new RuntimeException("Can't init datasource class.", e);
		}
    }
    
	@SuppressWarnings("rawtypes")
	private void setDataSourceProperties(DataSource dataSource, Properties properties)throws Exception{
		BeanWrapper dataSourceWrapper = new BeanWrapperImpl(dataSource);
		Iterator iterator = properties.keySet().iterator();
		while(iterator.hasNext()){
			Object key = iterator.next();
			String tempKey = (String)key;
			if (tempKey.startsWith("jdbc.")) {
				tempKey = tempKey.substring("jdbc.".length());
				if (!tempKey.equals("dataSourceClassName")){
					if (tempKey.equals("password.encrypt")){
						String encryptKey = System.getProperty("encrypt.key.data");
						String propValue = null;
						if (encryptKey != null){
							propValue = EncryptUtils.decrypt(properties.get(key).toString(), encryptKey);
						}else {
							propValue = EncryptUtils.decrypt(properties.get(key).toString());
						}
						dataSourceWrapper.setPropertyValue("password", propValue);
					} else {
						dataSourceWrapper.setPropertyValue(tempKey, properties.get(key));
					}
				}
			}
		}
	}

	public PrintWriter getLogWriter()throws SQLException{
		return this.dataSource.getLogWriter();
	}
	
	public void setLogWriter(PrintWriter out) throws SQLException{
	    this.dataSource.setLogWriter(out);
	}
	
	public void setLoginTimeout(int seconds) throws SQLException{
		this.dataSource.setLoginTimeout(seconds);
	}
	
	public int getLoginTimeout() throws SQLException{
		return this.dataSource.getLoginTimeout();
	}
	
	public Logger getParentLogger() throws SQLFeatureNotSupportedException{
		return this.dataSource.getParentLogger();
	}
	
	public <T> T unwrap(Class<T> clazz) throws SQLException{
		return this.dataSource.unwrap(clazz);
	}
	
	public boolean isWrapperFor(Class<?> clazz) throws SQLException{
		return this.dataSource.isWrapperFor(clazz);
	}
	
	public Connection getConnection() throws SQLException{
		return this.dataSource.getConnection();
	}
	
	public Connection getConnection(String username, String password) throws SQLException{
		return this.dataSource.getConnection(username, password);
	}
	
	public void setBeanName(String name){
		this.beanName = name;
	}
}